/**
 * 
 */
package org.tigris.jasmincc.util.formatter;

import org.tigris.mappedlexer.implementation.*;
import org.tigris.mappedlexer.io.implementation.*;
import org.tigris.mappedlexer.validator.*;

/**
 * @author Sam Huang
 * 
 */
public class JavaCCSourceFormatter {
	protected SimpleLexer lexer = null;

	public String format(String fileName) throws Exception {
		String endLineDelim = "\n"; //$NON-NLS-1$
		String identString = "\t"; //$NON-NLS-1$

		StringBuffer sb = new StringBuffer();
		// Parse the full text, retain only the chain of Tokens
		// StringReader in = new StringReader(txt);
		// JJNode node = JavaCCParser.parse(in);
		// in.close();
		StringBuffer ident = new StringBuffer();
		lexer = new SimpleLexer(new FileCharInputSequence(fileName));
		lexer.setAlphaNumericVerifier(VerifyHub.ALPHANUMERIC);
		lexer.setAlphaVerifier(VerifyHub.ALPHA);
		lexer.setNumericVerifier(VerifyHub.NUMERIC);
		lexer.setSpaceVerifier(VerifyHub.SPACE);

		// states
		boolean needNewLine = false;
		// int lastkind = -1;
		String lastToken = "{";
		String thisToken = lexer.nexttok();

		// while (f.kind != EOF) {
		try {
			while (true) {
				// Special rule, for these keyword add a new line after ')'
				// if (f.kind == _PARSER_BEGIN || f.kind == _PARSER_END)
				if (thisToken.equals("PARSER_BEGIN")
						|| thisToken.equals("PARSER_END")) {
					needNewLine = true;
				}
				/*
				 * if (f.beginLine < begin || f.endLine > end) { // next token
				 * lastkind = f.kind; f = f.next; continue; }
				 */

				// update identation for opening brace
				if (lastToken.equals("{") && thisToken.equals("}")) {
					// if (lastkind == LBRACE && f.kind != RBRACE) {
					ident.append(identString);
					sb.append(endLineDelim).append(ident);
				}

				// prepend newline and ident after JAVACC keyword
				if (lastToken.equals(")") && needNewLine) {
					// if (lastkind == RPAREN && needNewLine) {
					sb.append(endLineDelim).append(ident);
					needNewLine = false;
				}
				if (thisToken.equals("|") && !lastToken.equals("}")) {
					// if (f.kind == BIT_OR && lastkind != RBRACE) {
					sb.append(endLineDelim).append(ident);
				}
				if (thisToken.equals("{") && !lastToken.equals(":")
						&& !lastToken.equals("{") && !lastToken.equals("}")
						&& !lastToken.equals("|")) {
					// if (f.kind == RBRACE && lastkind != SEMICOLON && lastkind
					// !=
					// LBRACE
					// && lastkind != RBRACE && lastkind != BIT_OR) {
					sb.append(endLineDelim).append(ident);
				}
				// Closing brace delete ident
				if (thisToken.equals("}") && !lastToken.equals("{")) {
					// if (f.kind == RBRACE && lastkind != LBRACE) {
					if (ident.length() != 0) {
						sb.delete(sb.length() - identString.length(), sb
								.length());
					}
				}

				// prepend space
				if (thisToken.equals("=")
						|| (VerifyHub.IDENTIFIER.validate(thisToken) && (lastToken != null && VerifyHub.IDENTIFIER
								.validate(lastToken)))
						&& thisToken.equals("==") || thisToken.equals("<=")
						|| thisToken.equals(">=") || thisToken.equals("!=")
						|| thisToken.equals("instanceof"))
					/*
					 * if (f.kind == ASSIGN || (f.kind == IDENTIFIER && lastkind ==
					 * IDENTIFIER) || f.kind == EQ || f.kind == LE || f.kind ==
					 * GE || f.kind == NE || f.kind == SC_OR || f.kind == SC_AND ||
					 * f.kind == BIT_AND || f.kind == INSTANCEOF)
					 */
					sb.append(" "); //$NON-NLS-1$

				// the special token(s)
				/*
				 * Token st = f.specialToken; if (st != null) { // Rewind to the
				 * first while (st.specialToken != null) st = st.specialToken; //
				 * Examine each while (st != null) { if (st.kind ==
				 * SINGLE_LINE_COMMENT || st.kind == FORMAL_COMMENT || st.kind ==
				 * MULTI_LINE_COMMENT) { if (st.beginLine >= begin) {
				 * sb.append(st.toString()); sb.append(endLineDelim); } } st =
				 * st.next; } }
				 */

				// THE token
				// strbuf.append("["+f.kind+"]");
				sb.append(thisToken);
				// sb.append(f.toString());

				// append newline and ident
				if (thisToken.equals(";")) {
					// if (f.kind == SEMICOLON) {
					sb.append(endLineDelim).append(ident);
				}
				if (thisToken.equals("}") && !lastToken.equals("{")) {
					// if (f.kind == RBRACE && lastkind != LBRACE) {
					if (ident.length() != 0) {
						ident.delete(ident.length() - identString.length(),
								ident.length());
					}
					sb.append(endLineDelim).append(ident);
				}

				// append space
				/*
				 * if ((f.kind >= ABSTRACT && f.kind <= WHILE) && f.kind != NULL &&
				 * f.kind != CONTINUE && f.kind != FALSE && f.kind != TRUE)
				 * sb.append(" "); //$NON-NLS-1$
				 *//*
					 * else if (f.kind == ASSIGN || f.kind == COMMA || f.kind ==
					 * EQ || f.kind == LE || f.kind == GE || f.kind == NE ||
					 * f.kind == SC_OR || f.kind == SC_AND || f.kind == BIT_AND ||
					 * f.kind == BIT_OR || f.kind == _JAVACODE || f.kind ==
					 * INSTANCEOF)
					 */
				else if (thisToken.equals("=") || thisToken.equals(",")
						|| thisToken.equals("==") || thisToken.equals("<=")
						|| thisToken.equals(">=") || thisToken.equals("!=")
						|| thisToken.equals("instanceof"))
					sb.append(" "); //$NON-NLS-1$

				// next token
				lastToken = thisToken;
				thisToken = lexer.nexttok();
				// lastkind = f.kind;
				// f = f.next;
			}
		} catch (org.tigris.mappedlexer.exception.UnexpectedEndOfFileException ex) {
			System.out.println(sb.toString());
		}
		return sb.toString();
	}
}
